#include "../include/Room.hh"
#include "../include/Enemy.hh"
#include "../include/Item.hh"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <limits>
namespace Game {
    // Default constructor
    Room::Room() 
        : type_(Type::NORMAL), desc_("Empty Room"), 
          enemy_(nullptr), north_(nullptr), 
          east_(nullptr), south_(nullptr), west_(nullptr) {}

    // Parameterized constructor
    Room::Room(Type type, const std::string& desc) 
        : type_(type), desc_(desc), enemy_(nullptr),
          north_(nullptr), east_(nullptr), 
          south_(nullptr), west_(nullptr) {
        generateEnemy();
        generateLoot();
    }

    // Copy constructor
    Room::Room(const Room& other) 
        : type_(other.type_), desc_(other.desc_),
          enemy_(other.enemy_ ? other.enemy_->clone() : nullptr) {
        for (const auto& item : other.loot_) {
            loot_.push_back(std::make_unique<Item>(*item));
        }
        north_ = other.north_;
        east_ = other.east_;
        south_ = other.south_;
        west_ = other.west_;
    }

    // Assignment operator
    Room& Room::operator=(const Room& other) {
        if (this != &other) {
            type_ = other.type_;
            desc_ = other.desc_;
            enemy_ = other.enemy_ ? other.enemy_->clone() : nullptr;
            loot_.clear();
            for (const auto& item : other.loot_) {
                loot_.push_back(std::make_unique<Item>(*item));
            }
            north_ = other.north_;
            east_ = other.east_;
            south_ = other.south_;
            west_ = other.west_;
        }
        return *this;
    }

    // Connect rooms
    void Room::connect(Room* north, Room* east, Room* south, Room* west) {
        north_ = north;
        east_ = east;
        south_ = south;
        west_ = west;
    }

    // Handle room entry (trap/healing effects)
    void Room::enter(ICharacter& player) {
        switch (type_) {
            case Type::TRAP:{
                int damage = 20;
                player.takeDamage(damage);
                std::cout << ">> Entered a Trap Room! You lost " << damage << " HP!\n";
                std::cout << ">> Current HP: " << player.getHealth() << "\n";
                // Make sure the input buffer is cleared and wait for confirmation
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
                std::cout << "Press Enter to continue...";
                std::cin.get();
                break;
            }
            case Type::HEALING: {
                std::cout << "=== Healing Room ===\n";
                std::cout << "1. Restore 30 HP\n2. Leave\nChoice: ";
                int choice;
                std::cin >> choice;
                if (choice == 1) {
                    player.takeDamage(-30);
                    std::cout << ">> Healed 30 HP! Current HP: " << player.getHealth() << "\n";
                }
                // Make sure the input buffer is cleared and wait for confirmation
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
                std::cout << "Press Enter to continue...";
                std::cin.get();
                break;
            }
            case Type::BOSS:{
                if (!enemy_) generateEnemy();
                std::cout << ">> You encountered BOSS " << enemy_->getName() << "!\n";
                break;
            default:
                break;
            }
        }
    }

    // Generate enemy based on room type
    void Room::generateEnemy() {
        if (type_ == Type::BOSS) {
            enemy_ = Enemy::createBoss();
        } else if (type_ != Type::START && type_ != Type::HEALING) {
            // Forced enemy recognition
            int randType = rand() % 3;
            switch (randType) {
                case 0: enemy_ = Enemy::createGoblin(); break;
                case 1: enemy_ = Enemy::createSkeleton(); break;
                case 2: enemy_ = Enemy::createGoblinArcher(); break;
            }
        }
    }

    // Generate loot (70% chance for non-start rooms)
    void Room::generateLoot() {
        if (type_ != Type::START && rand() % 100 < 70) {
            int itemType = rand() % 4;
            switch (itemType) {
                case 0:
                    loot_.push_back(std::make_unique<Item>("Health Potion", 20, 0, 0, Item::HEALTH_POTION));
                    break;
                case 1:
                    loot_.push_back(std::make_unique<Item>("Sharp Sword", 0, 5, 0, Item::SWORD));
                    break;
                case 2:
                    loot_.push_back(std::make_unique<Item>("Iron Shield", 0, 0, 5, Item::SHIELD));
                    break;
                case 3:
                    loot_.push_back(std::make_unique<Item>("Magic Ring", 10, 3, 3, Item::MAGIC_RING));
                    break;
            }
        }
    }

    // Clear enemy from room
    void Room::clearEnemy() { 
        enemy_.reset(); 
    }

    // Getters
    Room::Type Room::getType() const { 
        return type_; 
    }

    std::string Room::getDesc() const { 
        return desc_; 
    }

    Enemy* Room::getEnemy() const { 
        return static_cast<Enemy*>(enemy_.get()); 
    }

    std::vector<std::unique_ptr<Item>>& Room::getLoot() { 
        return loot_; 
    }

    Room* Room::getNorth() const { 
        return north_; 
    }

    Room* Room::getEast() const { 
        return east_; 
    }

    Room* Room::getSouth() const { 
        return south_; 
    }

    Room* Room::getWest() const { 
        return west_; 
    }
}